package com.qd.panda.gas.sync;

import cn.hutool.core.exceptions.ExceptionUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.cdqidi.config.mybatis.handler.GeoPoint;
import com.cdqidi.constant.ConstantDto;
import com.cdqidi.dto.GeoPointDTO;
import com.cdqidi.exception.ApiException;
import com.cdqidi.util.GeoUtil;
import com.cdqidi.util.SortUtil;
import com.cdqidi.util.SpringContextHolder;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qd.common.panda.constant.PandaConstant;
import com.qd.common.panda.domain.entity.carpark.CarParkDTO;
import com.qd.common.panda.domain.entity.carpark.CarParkGasStationDTO;
import com.qd.common.panda.domain.enums.GasStationCompanyNameEnum;
import com.qd.common.panda.domain.enums.GasStationTypeEnum;
import com.qd.common.sys.constant.Constants;
import com.qd.common.sys.domain.entity.log.SendLogDTO;
import com.qd.common.sys.event.SendLogEvent;
import com.qd.panda.gas.station.ejiayou.EGasHttpServiceImpl;
import com.qd.panda.gas.station.ejiayou.resp.station.EGasPriceDTO;
import com.qd.panda.gas.station.ejiayou.resp.station.EGasStationDTO;
import com.qd.panda.model.*;
import com.qd.panda.service.park.*;
import com.qd.panda.service.stroke.BigDecimalUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 同步易加油的加油站数据
 *
 * @author sjk
 * @create 2023-02-13 11:01
 * @since 1.0.0
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class EGasSyncService {

    private static final String GAS_92 = "92#";
    private static final String GAS_95 = "95#";
    private static final String GAS_98 = "98#";
    private static final String GAS_0 = "0#";


    private final EGasHttpServiceImpl eGasHttpService;
    private final CarParkService carParkService;
    private final ParkHolderService parkHolderService;
    private final CarParkLocationService carParkLocationService;
    private final CarParkGasStationService carParkGasStationService;
    private final CarParkGasStationPriceService carParkGasStationPriceService;
    private final CarParkGasStationNozzleService carParkGasStationNozzleService;
    private final CarParkImgService carParkImgService;
    private final ObjectMapper objectMapper;


    @Transactional(rollbackFor = Exception.class)
    @SneakyThrows
    public void sync() {
        SendLogDTO sendLogDTO = new SendLogDTO();
        try {
            try {
                sendLogDTO.setSendState(ConstantDto.SF1);
                sendLogDTO.setLogType(PandaConstant.LOG_TYPE_GAS_STATIONS);
                sendLogDTO.setAddTime(LocalDateTime.now());
                sync(sendLogDTO);
            } finally {
                SpringContextHolder.publishEvent(new SendLogEvent(sendLogDTO));
            }
        } catch (Exception e) {
            final String message = ExceptionUtil.getMessage(e);
            sendLogDTO.setErrMsg(message);
            sendLogDTO.setSendState(ConstantDto.SF0);
            throw e;
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @SneakyThrows
    public void sync(SendLogDTO sendLogDTO) {
        long start = System.currentTimeMillis();
        List<EGasStationDTO> stations;
        try {
            stations = eGasHttpService.getStations(sendLogDTO);
        } finally {
            long end = System.currentTimeMillis();
            sendLogDTO.setTimeConsumer(end - start);
        }

        if (null == stations || stations.isEmpty()) {
            return;
        }
//        else {
//            sendLogDTO.setResponseMsg(stations.toString());
//        }
//        List<EGasStationDTO> stationList = stations.stream().filter(eGasStationDTO -> eGasStationDTO.getProvinceId().equals(510000)).collect(Collectors.toList());
        List<EGasStationDTO> stationList = stations;
        final int size = stationList.size();
        log.info("易加油四川加油站数量: {}", size);

        List<CarParkGasStation> addGasStationList = new ArrayList<>(size);
        List<CarParkGasStation> updateGasStationList = new ArrayList<>(size);
        List<CarParkImg> addCarParkImgList = new ArrayList<>(size * 2);
        List<CarParkImg> updateCarParkImgList = new ArrayList<>(size * 2);
        List<CarPark> addCarParkList = new ArrayList<>(size);
        List<CarParkLocation> addCarParkLocationList = new ArrayList<>(size);
        List<CarParkLocation> updateCarParkLocationList = new ArrayList<>(size);
        List<CarParkGasStationPrice> addGasPriceList = new ArrayList<>(size * 4);
        List<CarParkGasStationNozzle> addGasNozzleList = new ArrayList<>();

//        //测试代码，正式删除
//        List<EAdvertDTO> adverts = new ArrayList<>(1);
//        {
//
//            EAdvertDTO eAdvertDTO = new EAdvertDTO()
//                    .setId(1717)
//                    .setWeight(888)
//                    .setTitleWithinIcon("满100元享")
//                    .setTitleAfterIcon("前5升优惠，后续优惠见详情")
//                    .setSingleWordIcon("惠");
//            adverts.add(eAdvertDTO);
//
//            eAdvertDTO = new EAdvertDTO()
//                    .setId(1718)
//                    .setWeight(999)
//                    .setTitleWithinIcon("满200元享")
//                    .setTitleAfterIcon("前10升优惠，后续优惠见详情")
//                    .setSingleWordIcon("惠");
//            adverts.add(eAdvertDTO);
//
//            eAdvertDTO = new EAdvertDTO()
//                    .setId(1719)
//                    .setWeight(1000)
//                    .setTitleWithinIcon("满300元享")
//                    .setTitleAfterIcon("前20升优惠，后续优惠见详情")
//                    .setSingleWordIcon("惠");
//            adverts.add(eAdvertDTO);
//        }
//        //测试代码，正式删除

        for (EGasStationDTO station : stationList) {
//            //测试代码，正式删除
//            station.setAdverts(adverts);
//            //测试代码，正式删除

            String parkId = IdWorker.getIdStr();
            final String companyId = GasStationCompanyNameEnum.E_JIA_YOU.getCode();
            CarParkGasStation carParkGasStation = carParkGasStationService.getUniqueByGasStationCompanyNameAndStationId(companyId, station.getStationId() + "");
            if (null == carParkGasStation) {
                carParkGasStation = getCarParkGasStation(station, parkId, companyId);
                addGasStationList.add(carParkGasStation);
                buildCarPark(addCarParkList, station, parkId);
            } else {
                parkId = carParkGasStation.getPId();
                CarParkGasStation newCarParkGasStation = getCarParkGasStation(station, parkId, companyId);
                updateGasStationList.add(newCarParkGasStation);
            }
            carParkGasStationPriceService.deleteCarParkGasStationPriceByParkId(parkId);
            carParkGasStationNozzleService.deleteCarParkGasStationNozzleByParkId(parkId);

            for (EGasPriceDTO gasPriceDTO : station.getPrices()) {
                buildCarParkGasStationPrice(addGasPriceList, parkId, gasPriceDTO);
                buildCarParkGasStationNozzle(addGasNozzleList, parkId, gasPriceDTO);
            }
            buildLocation(addCarParkLocationList, updateCarParkLocationList, station, parkId);
            buildImg(addCarParkImgList, updateCarParkImgList, station, parkId);
        }
        if (!addGasStationList.isEmpty()) {
            carParkGasStationService.saveBatch(addGasStationList);
            addGasStationList.clear();
        }
        if (!updateGasStationList.isEmpty()) {
            carParkGasStationService.updateBatchIds(updateGasStationList);
            updateGasStationList.clear();
        }
        if (!addCarParkList.isEmpty()) {
            carParkService.saveBatch(addCarParkList);
            addCarParkList.clear();
        }
        if (!addCarParkImgList.isEmpty()) {
            carParkImgService.saveBatch(addCarParkImgList);
            addCarParkImgList.clear();
        }
        if (!updateCarParkImgList.isEmpty()) {
            carParkImgService.updateBatchIds(updateCarParkImgList);
            updateCarParkImgList.clear();
        }
        if (!addCarParkLocationList.isEmpty()) {
            carParkLocationService.saveBatch(addCarParkLocationList);
            addCarParkLocationList.clear();
        }
        if (!updateCarParkLocationList.isEmpty()) {
            carParkLocationService.updateBatchIds(updateCarParkLocationList);
            updateCarParkLocationList.clear();
        }
        if (!addGasPriceList.isEmpty()) {
            carParkGasStationPriceService.saveBatch(addGasPriceList);
            addGasPriceList.clear();
        }
        if (!addGasNozzleList.isEmpty()) {
            carParkGasStationNozzleService.saveBatch(addGasNozzleList);
            addGasNozzleList.clear();
        }
        //删除不存在的加油站
        delete(stationList);
        final List<CarParkGasStation> carParkGasStations = getCarParkGasStations();
        if (!carParkGasStations.isEmpty()) {
            //加载到缓存中
            carParkGasStations.forEach(carParkGasStation -> carParkService.updateToRedis(carParkGasStation.getPId(), null, null));
        }
        stations.clear();
    }

    private void buildImg(List<CarParkImg> addCarParkImgList, List<CarParkImg> updateCarParkImgList, EGasStationDTO station, String parkId) {
        String id = station.getStationId() + "_" + "stationPic.jpg";
        try {
            CarParkImg carParkImg = carParkImgService.getById(id);
            if (StringUtils.hasLength(station.getStationPic())) {
                if (null == carParkImg) {
                    carParkImg = new CarParkImg();
                    carParkImg.setPId(parkId);
                    carParkImg.setId(id);
                    carParkImg.setPicName("油站小图");
                    carParkImg.setIdx(1);
                    carParkImg.setPicPath(station.getStationPic());
                    addCarParkImgList.add(carParkImg);
                } else {
                    if (!carParkImg.getPicPath().equals(station.getStationPic())) {
                        carParkImg.setPicPath(station.getStationPic());
                        updateCarParkImgList.add(carParkImg);
                    }
                }
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("油站小图为空: {}", station.getStationId());
                }
            }
        } catch (Exception e) {
            log.error("油站小图为空: {}", station.getStationId());
            throw new ApiException(e);
        }

        id = station.getStationId() + "_" + "stationBannerPic.jpg";
        try {
            if (StringUtils.hasLength(station.getStationBannerPic())) {
                CarParkImg carParkImg = carParkImgService.getById(id);
                if (null == carParkImg) {
                    carParkImg = new CarParkImg();
                    carParkImg.setPId(parkId);
                    carParkImg.setPicName("油站大图");
                    carParkImg.setId(station.getStationId() + "_" + "stationBannerPic.jpg");
                    carParkImg.setIdx(2);
                    carParkImg.setPicPath(station.getStationBannerPic());
                    addCarParkImgList.add(carParkImg);
                } else {
                    if (!carParkImg.getPicPath().equals(station.getStationBannerPic())) {
                        carParkImg.setPicPath(station.getStationBannerPic());
                        updateCarParkImgList.add(carParkImg);
                    }
                }
            } else {
                if(log.isDebugEnabled()){
                    log.debug("油站大图为空: {}", station.getStationId());
                }
            }
        } catch (Exception e) {
            log.error("油站大图为空: {}", station.getStationId());
            throw new ApiException(e);
        }
    }

//    private void buildImg(List<CarParkImg> addCarParkImgList, EGasStationDTO station, String parkId) throws IOException {
//        String id = station.getStationId() + "_" + "stationPic.jpg";
//        try {
//            if (Boolean.FALSE.equals(carParkImgService.isExistsById(id))) {
//                if (StringUtils.hasLength(station.getStationPic())) {
//                    CarParkImg carParkImg = new CarParkImg();
//                    carParkImg.setPId(parkId);
//                    carParkImg.setId(id);
//                    carParkImg.setPicName("油站小图");
//                    carParkImg.setIdx(1);
//                    try (InputStream stream = URLUtil.getStream(URLUtil.url(station.getStationPic()))) {
//                        FileUtil.createFile(FileUtil.inputStreamToByte(stream), uploadDTO.getOfficialPath() + "e_gas", id);
//                    }
//                    carParkImg.setPicPath("e_gas" + File.separator + id);
//                    addCarParkImgList.add(carParkImg);
//                } else {
//                    log.error("油站小图为空: {}", station.getStationId());
//                }
//            }
//        } catch (Exception e) {
//            log.error("油站小图为空: {}", station.getStationId());
//            throw new ApiException(e);
//        }
//
//        id = station.getStationId() + "_" + "stationBannerPic.jpg";
//        try {
//            if (Boolean.FALSE.equals(carParkImgService.isExistsById(id))) {
//                if (StringUtils.hasLength(station.getStationBannerPic())) {
//                    CarParkImg carParkImg = new CarParkImg();
//                    carParkImg.setPId(parkId);
//                    carParkImg.setPicName("油站大图");
//                    carParkImg.setId(station.getStationId() + "_" + "stationBannerPic.jpg");
//                    carParkImg.setIdx(2);
//                    try (InputStream stream = URLUtil.getStream(URLUtil.url(station.getStationBannerPic()))) {
//                        FileUtil.createFile(FileUtil.inputStreamToByte(stream), uploadDTO.getOfficialPath() + "e_gas", id);
//                    }
//                    carParkImg.setPicPath("e_gas" + File.separator + id);
//                    addCarParkImgList.add(carParkImg);
//                } else {
//                    log.error("油站大图为空: {}", station.getStationId());
//                }
//            }
//        } catch (Exception e) {
//            log.error("油站大图为空: {}", station.getStationId());
//            throw new ApiException(e);
//        }
//
//    }


    private List<CarParkGasStation> getCarParkGasStations() {
        final CarParkGasStationDTO query = new CarParkGasStationDTO();
        query.setGasStationCompanyName(GasStationCompanyNameEnum.E_JIA_YOU.getCode());
        final List<CarParkGasStation> list = carParkGasStationService.getList(query);
        query.freeData();
        return list;
    }

    private void buildCarParkGasStationNozzle(List<CarParkGasStationNozzle> addGasNozzleList, String parkId, EGasPriceDTO gasPriceDTO) {
        final Set<String> nozzleNumberSet = new TreeSet<>(List.of(gasPriceDTO.getOilGunCodes()));
        for (String s : nozzleNumberSet) {
            CarParkGasStationNozzle carParkGasStationNozzle = new CarParkGasStationNozzle();
            carParkGasStationNozzle.setNozzleNumber(s);
            carParkGasStationNozzle.setPId(parkId);
            carParkGasStationNozzle.setOctaneNumber(gasValueToId(gasPriceDTO.getOilCode()));
            addGasNozzleList.add(carParkGasStationNozzle);
        }
    }


    private void buildCarParkGasStationPrice(List<CarParkGasStationPrice> addGasPriceList, String parkId, EGasPriceDTO gasPriceDTO) {
//        if (gasPriceDTO.getOilCode().equals(GAS_98)) {
//            //目前不处理98号枪
//            return;
//        }
        CarParkGasStationPrice carParkGasStationPrice = new CarParkGasStationPrice();
        carParkGasStationPrice.setPrice(new BigDecimal(gasPriceDTO.getCountryPrice()));
        carParkGasStationPrice.setCustomerPrice(new BigDecimal(gasPriceDTO.getDiscountPrice()));
        carParkGasStationPrice.setStationPrice(new BigDecimal(gasPriceDTO.getStationPrice()));
        carParkGasStationPrice.setCustomerDiscount(gasPriceDTO.getCustomerDiscount().doubleValue());
        carParkGasStationPrice.setOctaneNumber(gasValueToId(gasPriceDTO.getOilCode()));
        carParkGasStationPrice.setPId(parkId);
        Set<String> nozzleNumberSet = new TreeSet<>(List.of(gasPriceDTO.getOilGunCodes()));
        ArrayList<String> nozzleNumberList = new ArrayList<>(nozzleNumberSet);
        SortUtil.sortNumericAlphabet(nozzleNumberList);
        StringBuilder str = new StringBuilder();
        for (String s : nozzleNumberList) {
            str.append(s).append(",");
        }
        carParkGasStationPrice.setNozzleNumbers(str.substring(0, str.length() - 1));
        addGasPriceList.add(carParkGasStationPrice);
    }

    private void buildCarPark(List<CarPark> addCarParkList, EGasStationDTO station, String parkId) {
        if (Boolean.FALSE.equals(carParkService.isExistsById(parkId))) {
            CarPark carPark = new CarPark();
            carPark.setPId(parkId);
            carPark.setName(station.getStationName());
            carPark.setContactNumber(station.getPhone());
            carPark.setParkNum(0);
            carPark.setIntoFreeTime(0);
            carPark.setPayFreeTime(0);
            carPark.setCarParkType(PandaConstant.CAR_PARK_TYPE_0);
            carPark.setAddTime(LocalDateTime.now());
            carPark.setThirdPartyBill(ConstantDto.SF1);
            carPark.setConfirmIn(ConstantDto.SF0);
            carPark.setConfirmOut(ConstantDto.SF0);
            carPark.setOperator(Constants.ADMIN_DEFAULT_ID);
            carPark.setOrgId(Constants.DEFAULT_TREE_PARENT_ID);
            carPark.setEnable(ConstantDto.SF1);
            carPark.setParkType(PandaConstant.PARK_TYPE_GAS_STATION);
            carPark.setOwnBusiness(ConstantDto.SF0);
            carPark.setOnStreet(ConstantDto.SF0);
            carPark.setParkSpaceType(PandaConstant.PARK_SPACE_TYPE2);
            carPark.setEtcPay(ConstantDto.SF0);
            final CarParkDTO carParkDTO = carParkService.modelToDto(carPark);
            parkHolderService.buildQrCode(carParkDTO);
            addCarParkList.add(carParkService.dtoToModel(carParkDTO));
        }
    }

    private void buildLocation(List<CarParkLocation> addCarParkLocationList, List<CarParkLocation> updateCarParkLocationList, EGasStationDTO station, String parkId) {
        CarParkLocation location = carParkLocationService.getById(parkId);
        final double stationLat = Double.parseDouble(station.getLatitude());
        final double stationLng = Double.parseDouble(station.getLongitude());
        //百度坐标转gcj02
        GeoPointDTO geoPointDTO = GeoUtil.convertBD09ToGCJ02(stationLat, stationLng);
        if (null == location) {
            location = new CarParkLocation();
            addCarParkLocationList.add(location);
        } else {
//            if (location.getLat().equals(geoPointDTO.getLat()) && location.getLng().equals(geoPointDTO.getLng())) {
//                return;
//            }
            updateCarParkLocationList.add(location);
        }
        location.setPId(parkId);
        location.setAddress(station.getLocation());
        location.setLat(geoPointDTO.getLat());
        location.setLng(geoPointDTO.getLng());
        final GeoPoint geoPoint = new GeoPoint();
        geoPoint.setLat(geoPointDTO.getLat());
        geoPoint.setLng(geoPointDTO.getLng());
        location.setCityId(station.getCityId() + "");
        location.setCityName(station.getCityName());
        location.setProvinceId(station.getProvinceId() + "");
        location.setProvinceName(station.getProvinceName());
        location.setLocation(geoPoint);
        location.setLocationType(5);
    }

    private CarParkGasStation getCarParkGasStation(EGasStationDTO station, String parkId, String companyId) {
        CarParkGasStation carParkGasStation = new CarParkGasStation();
        carParkGasStation.setPId(parkId);
        carParkGasStation.setStationId(String.valueOf(station.getStationId()));
        carParkGasStation.setGasStationCompanyName(companyId);
        carParkGasStation.setStationType(coverStationType(station.getStationType()));
        final List<EGasPriceDTO> gasPrice = station.getPrices();
        if (!gasPrice.isEmpty()) {
            StringBuilder str = new StringBuilder();
            Set<String> set = new TreeSet<>();
            for (EGasPriceDTO gasPriceDTO : gasPrice) {
                set.addAll(new TreeSet<>(List.of(gasPriceDTO.getOilGunCodes())));
                try {
                    String stationPrice = gasPriceDTO.getStationPrice();
                    if (!StringUtils.hasLength(stationPrice)) {
                        stationPrice = "0";
                    }
                    String discountPrice = gasPriceDTO.getDiscountPrice();
                    if (!StringUtils.hasLength(discountPrice)) {
                        discountPrice = "0";
                    }
                    gasPriceDTO.setCustomerDiscount(BigDecimalUtil.calculateDiscount(new BigDecimal(stationPrice), new BigDecimal(discountPrice)).getCustomerDiscount());
                } catch (Exception e) {
                    log.error("parkId:{},stationId：{}", parkId, station.getStationId());
                }
            }
            //查询优惠最高的折扣,折扣值越小表示折扣越低
            AtomicReference<BigDecimal> customerDiscount = new AtomicReference<>();
            gasPrice.stream().map(EGasPriceDTO::getCustomerDiscount).min(BigDecimal::compareTo).ifPresent(customerDiscount::set);
            carParkGasStation.setCustomerDiscount(customerDiscount.get().doubleValue());
            final List<String> nozzleNumbers = new ArrayList<>(set);
            SortUtil.sortNumericAlphabet(nozzleNumbers);
            for (String nozzleNumber : nozzleNumbers) {
                str.append(nozzleNumber);
                str.append(",");
            }
            carParkGasStation.setNozzleNumbers(str.substring(0, str.length() - 1));
        }
        if (null != station.getAdverts() && !station.getAdverts().isEmpty()) {
            try {
                carParkGasStation.setAdvert(objectMapper.writeValueAsString(station.getAdverts()));
            } catch (JsonProcessingException ignored) {
            }
        }
        return carParkGasStation;
    }

    private void delete(List<EGasStationDTO> stations) {
        final List<CarParkGasStation> list = getCarParkGasStations();
        if (!list.isEmpty()) {
            List<String> deleteParkIds = new ArrayList<>();
            final List<String> ids = stations.stream().map(gasStationDTO -> String.valueOf(gasStationDTO.getStationId())).collect(Collectors.toList());
            for (CarParkGasStation carParkGasStation : list) {
                if (!ids.contains(carParkGasStation.getStationId())) {
                    deleteParkIds.add(carParkGasStation.getPId());
                }
            }
            if (!deleteParkIds.isEmpty()) {
                log.info("不存在的加油站,ids: {}", deleteParkIds);
                for (String parkId : deleteParkIds) {
                    carParkService.removeById(parkId);
                    carParkImgService.deleteCarParkImgByParkId(parkId);
                    carParkLocationService.removeById(parkId);
                    carParkGasStationService.removeById(parkId);
                    carParkGasStationPriceService.deleteCarParkGasStationPriceByParkId(parkId);
                    carParkGasStationNozzleService.deleteCarParkGasStationNozzleByParkId(parkId);
                }
            }
        }
    }

    private static String gasIdToValue(Integer id) {
        String value;
        switch (id) {
            case 0:
                value = GAS_0;
                break;
            case 92:
                value = GAS_92;
                break;
            case 95:
                value = GAS_95;
                break;
            case 98:
                value = GAS_98;
                break;
            default:
                throw new ApiException("无效的ID");
        }
        return value;
    }

    public static Integer gasValueToId(String value) {
        int id;
        switch (value) {
            case GAS_0:
                id = 0;
                break;
            case GAS_92:
                id = 92;
                break;
            case GAS_95:
                id = 95;
                break;
            case GAS_98:
                id = 98;
                break;
            default:
                throw new ApiException("无效的VALUE");
        }
        return id;
    }

    /**
     * 把易加油的加油站类型转换成系统类型
     *
     * @param stationType 油站类型 : 1 中石油，2 中石化，3 壳牌，4 其他
     * @return 系统加油站类型
     */
    private static String coverStationType(int stationType) {
        String id;
        switch (stationType) {
            case 1:
                id = GasStationTypeEnum.PETRO_CHINA.getCode();
                break;
            case 2:
                id = GasStationTypeEnum.SINOPEC.getCode();
                break;
            case 3:
                id = GasStationTypeEnum.SHELL.getCode();
                break;
            case 4:
                id = GasStationTypeEnum.GAS_TYPE_OTHER.getCode();
                break;
            default:
                throw new ApiException("StationType值错误");
        }
        return id;
    }

}